﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace VivendoByteToolkit.Helpers
{
    public static class SwipeCommandHelper
    {
        #region Up property
        public static ICommand GetUp(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(UpProperty);
        }

        public static void SetUp(DependencyObject obj,
            ICommand value)
        {
            obj.SetValue(UpProperty, value);
        }

        public static readonly DependencyProperty UpProperty =
            DependencyProperty.RegisterAttached("Up",
            typeof(ICommand),
            typeof(SwipeCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(Setup)));
        #endregion

        #region Down property
        public static ICommand GetDown(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(DownProperty);
        }

        public static void SetDown(DependencyObject obj,
            ICommand value)
        {
            obj.SetValue(DownProperty, value);
        }

        public static readonly DependencyProperty DownProperty =
            DependencyProperty.RegisterAttached("Down",
            typeof(ICommand),
            typeof(SwipeCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(Setup))); 
        #endregion

        #region Right property
        public static ICommand GetRight(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(RightProperty);
        }

        public static void SetRight(DependencyObject obj,
            ICommand value)
        {
            obj.SetValue(RightProperty, value);
        }

        public static readonly DependencyProperty RightProperty =
            DependencyProperty.RegisterAttached("Right",
            typeof(ICommand),
            typeof(SwipeCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(Setup)));
        #endregion

        #region Left property
        public static ICommand GetLeft(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(LeftProperty);
        }

        public static void SetLeft(DependencyObject obj,
            ICommand value)
        {
            obj.SetValue(LeftProperty, value);
        }

        public static readonly DependencyProperty LeftProperty =
            DependencyProperty.RegisterAttached("Left",
            typeof(ICommand),
            typeof(SwipeCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(Setup)));
        #endregion

        #region Attached (to avoid to subscribe the event 'ManipulationCompleted' multiple times
        public static bool GetAttached(DependencyObject obj)
        {
            return (bool)obj.GetValue(AttachedProperty);
        }

        public static void SetAttached(DependencyObject obj,
            bool value)
        {
            obj.SetValue(AttachedProperty, value);
        }

        private static readonly DependencyProperty AttachedProperty =
            DependencyProperty.RegisterAttached("Attached",
            typeof(bool),
            typeof(FrameworkElement),
            new PropertyMetadata(false)); 
        #endregion

        private static void Setup(DependencyObject obj,
            DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement ctl = obj as FrameworkElement;

            if (ctl != null)
            {
                ICommand oldValue = (ICommand)e.OldValue;
                ICommand newValue = (ICommand)e.NewValue;

                if (oldValue == null && newValue != null)
                {
                    {
                        if (GetAttached(ctl) == false)
                        {
                            ctl.ManipulationMode = ManipulationModes.TranslateX |
                                ManipulationModes.TranslateY;
                            SetAttached(ctl, true);
                            ctl.ManipulationCompleted += ctl_ManipulationCompleted;
                        }
                    }
                }
                else if (oldValue != null && newValue == null)
                {
                    ctl.ManipulationMode = ManipulationModes.None;
                    ctl.SetValue(AttachedProperty, false);
                    ctl.ManipulationCompleted -= ctl_ManipulationCompleted;
                }
            }
        }

        static void ctl_ManipulationCompleted(object sender,
            ManipulationCompletedRoutedEventArgs e)
        {
            var element = sender as FrameworkElement;
            ICommand command = null;

            // x < 0 --> verso sinistra
            // x > 0 --> verso destra
            var x = e.Cumulative.Translation.X;

            // y < 0 --> verso l'alto
            // y > 0 --> verso il basso
            var y = e.Cumulative.Translation.Y;

            if (y < 0 && Math.Abs(y) > Math.Abs(x))
            {
                command = GetUp(element);
            }
            else if (y > 0 && Math.Abs(y) > Math.Abs(x))
            {
                command = GetDown(element);
            }
            else if (x > 0 && Math.Abs(x) > Math.Abs(y))
            {
                command = GetRight(element);
            }
            else if (x < 0 && Math.Abs(x) > Math.Abs(y))
            {
                command = GetLeft(element);
            }

            if (command != null)
            {
                if (command.CanExecute(null))
                {
                    command.Execute(null);
                }
            }
        }
    }
}